﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Configuration;
using System.ComponentModel;
using System.Text;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

[assembly: WebResource("com.cruxomatic.items.navigationstrip.jquery-1.2.3.js", "text/javascript")]
[assembly: ScriptResource("com.cruxomatic.items.navigationstrip.jquery-1.2.3.js", "com.cruxomatic.items.navigationstrip", "com.cruxomatic.items.navigationstrip.Resource")]
[assembly: WebResource("com.cruxomatic.items.navigationstrip.VistaAddressBar.VistaAddressBar.js", "text/javascript")]
[assembly: ScriptResource("com.cruxomatic.items.navigationstrip.VistaAddressBar.VistaAddressBar.js", "com.cruxomatic.items.navigationstrip.VistaAddressBar", "com.cruxomatic.items.navigationstrip.Resource")]
namespace com.cruxomatic.items.navigationstrip
{
    [Serializable]
    [XmlRoot("UrlTreeNode")]
    public class UrlTreeNode
    {
        private string name;
        private string url;
        private string tag;
        private bool clickable = true;

        private UrlTreeNode parent;
        private List<UrlTreeNode> children;

        public UrlTreeNode()
        {
        }

        public UrlTreeNode(string nodeName, string nodeUrl)
        {
            name = nodeName;
            url = nodeUrl;
        }

        public UrlTreeNode(string nodeName, string nodeUrl, string nodeTag)
        {
            name = nodeName;
            url = nodeUrl;
            tag = nodeTag;
        }

        public UrlTreeNode(string nodeName, string nodeUrl, string nodeTag, bool isClickable)
        {
            name = nodeName;
            url = nodeUrl;
            tag = nodeTag;
            clickable = isClickable;
        }

        [XmlAttribute]
        public virtual string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlAttribute]
        public virtual string Url
        {
            get { return url; }
            set { url = value; }
        }

        [XmlAttribute]
        public string Tag
        {
            get { return tag; }
            set { tag = value; }
        }

        [XmlAttribute]
        public bool Clickable
        {
            get { return clickable; }
            set { clickable = value; }
        }

        [XmlElement]
        public virtual List<UrlTreeNode> Children
        {
            get { return children; }
            //internal set { children = value; }
            set { children = value; }
        }

        [XmlIgnore]
        public virtual UrlTreeNode Parent
        {
            get { return parent; }
            //protected internal set { parent = value; }
            set { parent = value; }
        }

        public virtual void AddParentNode(UrlTreeNode parentNode)
        {
            if (parentNode == null) return;
            parentNode.AddChildNode(this);
            parent = parentNode;
        }

        public virtual void AddChildNode(UrlTreeNode node)
        {
            if (node == null) return;
            node.parent = this;
            if (children == null) children = new List<UrlTreeNode>();
            children.Add(node);
        }

        public virtual void AddChildNode(string nodeName, string nodeUrl)
        {
            if (string.IsNullOrEmpty(nodeName) || string.IsNullOrEmpty(nodeUrl)) return;
            UrlTreeNode node = new UrlTreeNode(nodeName, nodeUrl);
            AddChildNode(node);
        }

        public virtual void RemoveChildNode(UrlTreeNode node)
        {
            RemoveChildNode(node.Name);
        }

        public virtual void RemoveChildNode(string nodeName)
        {
            foreach (UrlTreeNode childNode in children.ToArray())
            {
                if (childNode.Name.Equals(nodeName))
                {
                    children.Remove(childNode);
                }
            }
        }

        public virtual string GetNodeUrl()
        {
            return GetUrl(this, false);
        }

        public virtual string GetTagUrl()
        {
            return GetUrl(this, true);
        }

        protected virtual string GetUrl(UrlTreeNode node, bool useTag)
        {
            if (node == null)
                return string.Empty;
            if (node.Parent == null)
                return node.Name;
            return GetUrl(node.Parent, useTag) + "/" + (useTag ? node.Tag : node.Name);
        }
    }
    public class LinkButtonEventArgs : EventArgs
    {
        private UrlTreeNode treeNode;

        public UrlTreeNode TreeNode
        {
            get { return treeNode; }
            set { treeNode = value; }
        }

        public LinkButtonEventArgs(UrlTreeNode node)
        {
            treeNode = node;
        }
    }
    public delegate void LinkButtonHandler(object sender, LinkButtonEventArgs e);

    [Serializable]
    public class VistaAddressBar : WebControl, INamingContainer
    {
        private ClientScriptManager cs;
        public event LinkButtonHandler LinkButtonEvent;
        public event LinkButtonHandler NewLinkEvent;
        Panel outerPanel;
        Panel floatingPanel;


        private List<UrlTreeNode> address;
        private UrlTreeNode tree;
        private string closedImageUrl;
        private string openImageUrl;
        private string listImageUrl;
        private Int32 listWidth;
        private Int32 listSize;


        private bool autoRedirect;
        private Int32 listOffsetLeft;

        public VistaAddressBar()
        {
        }

        #region Properties

        public List<UrlTreeNode> Address
        {
            get
            {
                address = (List<UrlTreeNode>)ViewState["UrlTreeNodeList"];
                if (address == null)
                {
                    address = new List<UrlTreeNode>();
                    address.Add(Tree);
                }
                ViewState["UrlTreeNodeList"] = address;
                return address;
            }
            set
            {
                address = value;
                ViewState["UrlTreeNodeList"] = address;
            }
        }

        public UrlTreeNode Tree
        {
            get
            {
                tree = (UrlTreeNode)ViewState["AddressTree"];
                return tree;
            }
            set
            {
                tree = value;
                ViewState["AddressTree"] = tree;
            }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string ClosedImageUrl
        {
            get { return closedImageUrl; }
            set { closedImageUrl = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string OpenImageUrl
        {
            get { return openImageUrl; }
            set { openImageUrl = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string ListImageUrl
        {
            get { return listImageUrl; }
            set { listImageUrl = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue(100)]
        [Localizable(true)]
        public Int32 ListWidth
        {
            get { return listWidth; }
            set { listWidth = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public Int32 ListSize
        {
            get { return listSize; }
            set { listSize = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue(false)]
        [Localizable(true)]
        public bool AutoRedirect
        {
            get { return autoRedirect; }
            set { autoRedirect = value; }
        }

        [Bindable(false)]
        [Category("Target Control Appearance")]
        [DefaultValue(25)]
        [Localizable(true)]
        public Int32 ListOffsetLeft
        {
            get
            {
                if (listOffsetLeft <= 0) listOffsetLeft = 25;
                return listOffsetLeft;
            }
            set { listOffsetLeft = value; }
        }

        public String DropButtonClicked
        {
            get { return (String)ViewState["DropButtonClicked"]; }
            set { ViewState["DropButtonClicked"] = value; }
        }

        List<UrlTreeNode> childList;
        public List<UrlTreeNode> ChildList
        {
            get
            {
                if (childList == null) childList = (List<UrlTreeNode>)ViewState["ChildList"];
                return childList;
            }
            set
            {
                childList = value;
                ViewState["ChildList"] = childList;
            }
        }

        #endregion

        #region Overriden properties
        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }
        #endregion Overriden properties

        #region Local Methods

        protected virtual Panel CreateFloatingPanel(UrlTreeNode node)
        {
            if (node.Children == null) return null;
            Panel floater = new Panel();
            //floater.Attributes.Add("onclick", "animateFloater(this)");
            floater.ID = "vabFloatingPanel";
            floater.CssClass = "vabFloatingPanel";
            floater.Style.Add(HtmlTextWriterStyle.Position, "absolute");
            floater.Style.Add(HtmlTextWriterStyle.ZIndex, Int16.MaxValue.ToString());
            Table tbl = new Table();
            tbl.CellPadding = 0;
            tbl.CellSpacing = 0;
            tbl.CssClass = "vabFloatingList";

            Int32 ItmNo = 0;
            foreach (UrlTreeNode childNode in node.Children)
            {
                TableRow row = new TableRow();
                TableCell cell1 = new TableCell();
                cell1.VerticalAlign = VerticalAlign.Middle;
                cell1.HorizontalAlign = HorizontalAlign.Center;
                cell1.CssClass = "vavListImageCellPadding";

                Image listImg = new Image();
                listImg.ImageUrl = ListImageUrl;

                cell1.Controls.Add(listImg);

                TableCell cell2 = new TableCell();
                cell2.VerticalAlign = VerticalAlign.Middle;
                cell2.HorizontalAlign = HorizontalAlign.Left;

                Button btnLink = new Button();
                btnLink.ID = "vabListBtn" + ItmNo;
                btnLink.CssClass = "vabListButton";
                btnLink.Attributes.Add("onmouseover", "this.className = 'vabListButton_over';");
                btnLink.Attributes.Add("onmouseout", "this.className = 'vabListButton';");
                btnLink.Attributes.Add("onmousedown", "this.className = 'vabListButton_down';");
                btnLink.CausesValidation = false;
                btnLink.Text = childNode.Name;
                btnLink.Attributes.Add("Url", childNode.Url);
                btnLink.Click += ListButton_Click;

                cell2.Controls.Add(btnLink);

                row.Cells.Add(cell1);
                row.Cells.Add(cell2);

                tbl.Rows.Add(row);

                ItmNo++;
            }

            if (ListSize > 0 && ItmNo > ListSize)
            {
                floater.Height = Unit.Pixel(ListSize * 20);
                floater.Style.Add(HtmlTextWriterStyle.Height, floater.Height.Value.ToString());
                floater.Style.Add(HtmlTextWriterStyle.Overflow, "auto");
            }

            floater.Controls.Add(tbl);

            return floater;
        }
        protected virtual Panel CreateAddressBar()
        {
            Panel outer = new Panel();
            outer.ID = "vabOuterPanel";
            outer.Style.Add(HtmlTextWriterStyle.Position, "relative");
            outer.Style.Add(HtmlTextWriterStyle.Left, "0px");
            outer.CssClass = "vab";

            HiddenField hf = new HiddenField();
            hf.ID = "hiddenCoords";

            outer.Controls.Add(hf);

            Panel innerPanel = new Panel();
            innerPanel.CssClass = "vabTable";
            innerPanel.Style.Add(HtmlTextWriterStyle.ZIndex, Int16.MaxValue.ToString());
            Int32 itemCount = 0;
            foreach (UrlTreeNode node in Address)
            {
                var btnText = new LinkButton();
                btnText.ID = "btnText" + itemCount;
                btnText.Attributes.Add("Url", node.Url);
                btnText.Text = node.Name;
                btnText.CssClass = "vabUrl";
                btnText.CausesValidation = false;
                btnText.EnableTheming = false;
                if (node.Clickable)
                {
                    //btnText.Attributes.Add("onmouseover", "this.className = 'vabUrl_over';");
                    //btnText.Attributes.Add("onmouseout", "this.className = 'vabUrl';");
                    //btnText.Attributes.Add("onmousedown", "this.className = 'vabUrl_down';");
                    if (autoRedirect)
                    {
                        btnText.Attributes.Add("onclick", "location.href='" + HttpContext.Current.Request.ApplicationPath + node.Url + "'; return false;");
                    }
                    else
                    {
                        btnText.Click += TextButton_Click;
                    }
                    innerPanel.Controls.Add(btnText);
                }
                else
                {
                    Label lblNode = new Label
                                        {
                                            EnableTheming = false,
                                            Text = btnText.Text,
                                            CssClass = "vabNonClickableNode"
                                        };
                    innerPanel.Controls.Add(lblNode);
                }


                if (node.Children != null)
                {
                    Image imgVab = new Image();
                    imgVab.ID = "imgVab" + itemCount;
                    imgVab.CssClass = "vabArrow";
                    imgVab.ImageAlign = ImageAlign.AbsMiddle;
                    imgVab.ImageUrl = ClosedImageUrl;
                    innerPanel.Controls.Add(imgVab);
                }
                itemCount++;
            }

            //Add table to outer panel
            outer.Controls.Add(innerPanel);

            return outer;
        }
        protected virtual void RemoveFloatingPanel()
        {
            Panel panel = (Panel)this.FindControl("vabFloatingPanel");
            if (panel != null)
            {
                this.Controls.Remove(panel);
                ChildList = null;
                floatingPanel = null;
            }
            DropButtonClicked = null;
        }
        protected virtual Int32[] CalculatePanelPosition()
        {
            Int32 _top = 0, _left = 0, _scrwidth = 0;
            HiddenField hf = (HiddenField)FindControl("hiddenCoords");
            if (hf != null)
            {
                string pos = hf.Value;
                if (!string.IsNullOrEmpty(pos))
                {
                    string[] position = pos.Split(',');
                    _left = Int32.Parse(position[0]);
                    _top = Int32.Parse(position[1]);
                    _scrwidth = Int32.Parse(position[2]);
                }
            }

            if (ListWidth > (_scrwidth - _left))
            {
                _left -= (ListWidth - (_scrwidth - _left));
            }

            Int32[] coords = new Int32[3];
            coords[0] = _left - (ListOffsetLeft <= 0 ? 25 : ListOffsetLeft);
            coords[1] = _top;
            coords[2] = _scrwidth;

            return coords;
        }

        #endregion

        #region Event Handlers

        private void DropButton_Click(object sender, ImageClickEventArgs e)
        {
            ImageButton btn = (ImageButton)sender;

            if (DropButtonClicked != null && btn.ID.Equals(DropButtonClicked))
            {
                RemoveFloatingPanel();
                btn.ImageUrl = closedImageUrl;
            }
            else
            {
                btn.ImageUrl = openImageUrl;
                DropButtonClicked = btn.ID;
                Int32 itmNo = Int32.Parse(btn.ID.Substring(3));
                for (int btnCount = 0; btnCount < Address.Count; btnCount++)
                {
                    if (btnCount != itmNo)
                    {
                        ImageButton ImgBtn = (ImageButton)outerPanel.FindControl("btn" + btnCount);
                        if (ImgBtn != null) ImgBtn.ImageUrl = closedImageUrl;
                    }
                }

                //Calculate Position for Floating Panel
                Int32[] position = CalculatePanelPosition();

                if (Address != null && Address.Count > itmNo)
                {
                    floatingPanel = CreateFloatingPanel(Address[itmNo]);
                    if (position[0] > 0 && floatingPanel != null)
                    {
                        floatingPanel.Style.Add(HtmlTextWriterStyle.Left, position[0].ToString() + "px");
                    }
                    //string floatingPanelID = this.ClientID + "_" + floatingPanel.ID;
                    //this.Attributes.Add("onload", "$('" + floatingPanelID + "').slideDown('slow');");
                    ViewState["SelectedChildList"] = itmNo;
                    ChildList = Address[itmNo].Children;
                }
            }
        }
        private void ListButton_Click(object sender, EventArgs e)
        {
            Int32 itmNo = (Int32)ViewState["SelectedChildList"];
            for (int i = Address.Count - 1; i > itmNo; i--)
            {
                Address.RemoveAt(i);
            }

            //Add new item to the list
            Button selButton = (Button)sender;
            Int32 selItem = Int32.Parse(selButton.ID.Substring(10));

            Address.Add(Address[Address.Count - 1].Children[selItem]);
            if (NewLinkEvent != null)
            {
                LinkButtonEventArgs ev = new LinkButtonEventArgs(
                    Address[Address.Count - 1]);
                NewLinkEvent(this, ev);
            }
            RemoveFloatingPanel();

            Controls.Clear();
            Controls.Add(CreateAddressBar());
        }
        private void TextButton_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            Int32 itmNo = Int32.Parse(btn.ID.Substring(7));
            for (int i = Address.Count - 1; i > itmNo; i--)
            {
                Address.RemoveAt(i);
            }

            RemoveFloatingPanel();

            if (LinkButtonEvent != null)
            {
                LinkButtonEvent(this, new LinkButtonEventArgs(Address[itmNo]));
            }
        }

        #endregion

        #region Overrides

        protected override void CreateChildControls()
        {
            Controls.Clear();

            outerPanel = CreateAddressBar();
            Controls.Add(outerPanel);

            if (ChildList != null)
            {
                floatingPanel = CreateFloatingPanel(ChildList[0].Parent);
                Controls.Add(floatingPanel);
            }
            base.CreateChildControls();
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            cs = Page.ClientScript;
            cs.RegisterClientScriptResource(typeof(com.cruxomatic.items.navigationstrip.VistaAddressBar),
                "com.cruxomatic.items.navigationstrip.jquery-1.2.3.js");
            cs.RegisterClientScriptResource(typeof(com.cruxomatic.items.navigationstrip.VistaAddressBar),
                "com.cruxomatic.items.navigationstrip.VistaAddressBar.VistaAddressBar.js");

        }
        protected override void Render(HtmlTextWriter writer)
        {
            Controls.Clear();

            Controls.Add(CreateAddressBar());
            if (floatingPanel != null && ChildList != null) Controls.Add(floatingPanel);

            base.Render(writer);
        }

        #endregion

        #region Control Methods

        public void CreateTreeFromXml(string xml)
        {
            try
            {
                XmlSerializer xs = new XmlSerializer(typeof(UrlTreeNode));
                ASCIIEncoding encoding = new ASCIIEncoding();
                byte[] byteArray = encoding.GetBytes(xml);
                MemoryStream memoryStream = new MemoryStream(byteArray);
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII);
                Tree = (UrlTreeNode)xs.Deserialize(memoryStream);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Illformed XML : " + ex.Message);
            }
        }
        protected UrlTreeNode RecursiveAddNode(SiteMapNode mapNode)
        {
            UrlTreeNode newNode = new UrlTreeNode(mapNode.Title, mapNode.Url, mapNode.ResourceKey);
            if (mapNode.HasChildNodes)
            {
                for (int i = 0; i < mapNode.ChildNodes.Count; i++)
                {
                    SiteMapNode childNode = mapNode.ChildNodes[i];
                    newNode.AddChildNode(RecursiveAddNode(childNode));
                }
            }
            return newNode;
        }
        public void CreateTreeFromSiteMap()
        {
            SiteMapNode root = SiteMap.RootNode;

            Tree = new UrlTreeNode(root.Title, root.Url, root.ResourceKey);
            if (!root.HasChildNodes) return;
            for (int i = 0; i < root.ChildNodes.Count; i++)
            {
                SiteMapNode childNode = root.ChildNodes[i];
                Tree.AddChildNode(RecursiveAddNode(childNode));
            }
        }
        public void SetAddressByNamedUrl(string namedUrl)
        {
            string[] urlParts = namedUrl.Split('/');

            if (string.IsNullOrEmpty(urlParts[0].Trim())) urlParts[0] = "Home";

            if (urlParts != null && urlParts.Length > 0)
            {
                UrlTreeNode mainTree = Tree;
                Address.Clear();
                Address.Add(Tree);
                for (int ctr = 1; ctr < urlParts.Length; ctr++)
                {
                    foreach (UrlTreeNode node in mainTree.Children.ToList())
                    {
                        if (node.Name.Equals(urlParts[ctr]))
                        {
                            mainTree = node;
                            Address.Add(node);
                            break;
                        }
                    }
                }
            }
        }
        public void SetAddressByTagUrl(string tagUrl)
        {
            string[] urlParts = tagUrl.Split('/');

            if (string.IsNullOrEmpty(urlParts[0].Trim())) urlParts[0] = "Home";

            if (urlParts != null && urlParts.Length > 0)
            {
                UrlTreeNode mainTree = Tree;
                Address.Clear();
                Address.Add(Tree);
                for (int ctr = 1; ctr < urlParts.Length; ctr++)
                {
                    foreach (UrlTreeNode node in mainTree.Children.ToList())
                    {
                        if (node.Tag.Equals(urlParts[ctr]))
                        {
                            mainTree = node;
                            Address.Add(node);
                            break;
                        }
                    }
                }
            }
        }

        #endregion

    }
}
